package com.gryffonx.artgenerator;

import org.dom4j.io.SAXReader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.tree.DefaultElement;

import java.io.File;
import java.util.List;
import java.util.ArrayList;

import com.gryffonx.DiceRoller.StaticDiceRoller;
import com.gryffonx.utils.StringUtils;

public class ArtworkIdeaGenerator {
    StringBuffer idea;
    boolean outdoors = false;
    boolean single = true;
    private static final File fileToBeParsed = new File("src/com/gryffonx/xml/artwork.xml");
    private static final SAXReader reader = new SAXReader();
    private static Document xmlDoc = null;
    private static int ACTOR_MAIN = 0;
    private static int ACTOR_ADV = 1;
    private static int PLACEMENT_PRIMARY = 0;
    private static int PLACEMENT_ADDITIONAL = 1;

    public ArtworkIdeaGenerator(){

        try {
            xmlDoc = reader.read(fileToBeParsed);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String generateDescription(IdeaBean idea){
        StringBuffer retVal = new StringBuffer();
        retVal.append("\r\n");
        retVal.append("A ");
        retVal.append(idea.getNumberOfActors().toLowerCase()).append(" ");
        if (!idea.getNumberOfActors().equals("Single")){
             retVal.append("of ");
        }
        retVal.append(idea.getActors().toLowerCase());
        if (!idea.getNumberOfActors().equals("Single")){
             retVal.append("'s ");
        }
        if (!idea.getNumberOfActors().equals("Single")){
            retVal.append("are ");
        }else{
            retVal.append(" is ");
        }

        retVal.append(idea.getLocationName().toLowerCase()).append(", ");
        retVal.append(idea.getActionName().toLowerCase()).append(" ");
        if (idea.getActionType().equals("with")){
            retVal.append(" with a ");

            retVal.append(idea.getAdversaryNumber().toLowerCase()).append(" ");
            if (!idea.getAdversaryNumber().equals("Single")){
                 retVal.append("of ");
            }
            retVal.append(idea.getAdversaryName().toLowerCase());
            if (!idea.getAdversaryNumber().equals("Single")){
                 retVal.append("'s ");
            }
        }
        if (idea.getLocationType().equals("outdoors")){
            retVal.append("at ");
            retVal.append(idea.getTimeOfDay().toLowerCase()).append(" ");
            retVal.append("during ");
            retVal.append(idea.getSeason().toLowerCase());           
        }

        if (idea.getBackgroundElements().size() > 0){
            retVal.append("\r\nBackground elements include: ");
            for (int i=0; i<idea.getBackgroundElements().size(); i++){
                String element = idea.getBackgroundElements().get(i).toString();
                retVal.append(element).append(", ");
            }
        }

        retVal.append("\r\n");
        retVal.append("USER NOTES:------------------------------------------------------------------------");
        retVal.append("\r\n");
        return retVal.toString();


    }

    public String generateIdea() throws Exception {
        IdeaBean bean = new IdeaBean();
        //get number of main characters...
        getNumber(bean, ACTOR_MAIN);

        //get character types...
        getActor(bean, ACTOR_MAIN, PLACEMENT_PRIMARY);

        //get location and action being performed in that location...
        getLocation(bean);
        if (bean.getActionType().equals("with")){
            //get a partner...
            getNumber(bean, ACTOR_ADV);
            getActor(bean, ACTOR_MAIN, PLACEMENT_ADDITIONAL);
        }else if (bean.getActionType().equals("against")){
            //get an opponent
            getNumber(bean, ACTOR_ADV);
            getActor(bean, ACTOR_ADV, PLACEMENT_PRIMARY);
        }
        if (bean.getLocationType().equals("outdoors")){
            //get time of year...
            getSeason(bean);

            //get time of day...
            getTime(bean);

            //add weather effect...

            //randomly "flip a coin" to determine whether specific background elements should be added...
            int flip = StaticDiceRoller.rolldSomething(2, 1, true);
            if (flip == 1){
                bean.setBackgroundElements(generateBackgroundElements("outdoors"));
            }
        }else{
            //randomly "flip a coin" to determine whether specific background elements should be added...
            int flip = StaticDiceRoller.rolldSomething(2, 1, true);
            if (flip == 1){
                bean.setBackgroundElements(generateBackgroundElements("indoors"));
            }

        }

        return generateDescription(bean);
    }

    private ArrayList generateBackgroundElements(String type) throws Exception {
        ArrayList retVal = new ArrayList();
        if (type.equals("outdoors")){
            List nodes = xmlDoc.selectNodes("/artwork/backdrops/outdoor/backdrop");
            int howMany = StaticDiceRoller.rolldSomething(nodes.size(), 1, true);
            for (int i=0; i<howMany; i++){
                int roll = StaticDiceRoller.rolldSomething(nodes.size(), 1, true);
                if (roll > 0){
                    DefaultElement element = (DefaultElement)nodes.get(roll-1);
                    String backdropText = element.getStringValue();
                    if (!retVal.contains(backdropText)){
                        retVal.add(element.getStringValue());
                    }
                }
            }
        }else{
            List nodes = xmlDoc.selectNodes("/artwork/backdrops/indoor/backdrop");
            int howMany = StaticDiceRoller.rolldSomething(nodes.size(), 1, true);
            for (int i=0; i<howMany; i++){
                int roll = StaticDiceRoller.rolldSomething(nodes.size(), 1, true);
                if (roll > 0){
                    DefaultElement element = (DefaultElement)nodes.get(roll-1);
                    String backdropText = element.getStringValue();
                    if (!retVal.contains(backdropText)){
                        retVal.add(element.getStringValue());
                    }
                }
            }

        }

        return retVal;
    }

    private void getNumber(IdeaBean bean, int type) throws Exception {
        if (type == ACTOR_MAIN){
            List nodes = xmlDoc.selectNodes("/artwork/howmany/count[@name='Single']");
            int howMany = nodes.size();
            int roll = StaticDiceRoller.rolldSomething(howMany, 1, true);
            if (roll > 0) {
                DefaultElement element = (DefaultElement)nodes.get(roll-1);
                bean.setNumberOfActors(element.attribute("name").getStringValue());
            }
            
        }else if (type == ACTOR_ADV){
            List nodes = xmlDoc.selectNodes("/artwork/howmany/count");
            int howMany = nodes.size();
            int roll = StaticDiceRoller.rolldSomething(howMany, 1, true);
            if (roll > 0) {
                DefaultElement element = (DefaultElement)nodes.get(roll-1);
                bean.setAdversaryNumber(element.attribute("name").getStringValue());
            }
        }
    }

    private void getActor(IdeaBean bean, int type, int placement) throws Exception {
        if (type == ACTOR_MAIN){
            List actorTypeNodes = xmlDoc.selectNodes("/artwork/actors/actor[@name='People']");
            int actorTypeCount = actorTypeNodes.size();
            int typeRoll = StaticDiceRoller.rolldSomething(actorTypeCount, 1, true);
            if (typeRoll > 0) {
                DefaultElement actorTypeElement = (DefaultElement)actorTypeNodes.get(typeRoll-1);
                String newPath = actorTypeElement.getPath() + "[@name='People']/what/element";
                List actorList = xmlDoc.selectNodes(newPath);
                int actorCount = actorList.size();
                int actorListRoll = StaticDiceRoller.rolldSomething(actorCount, 1, true);
                if (actorListRoll > 0) {
                    DefaultElement newelement = (DefaultElement)actorList.get(actorListRoll-1);
                    if (placement == PLACEMENT_PRIMARY){
                        bean.setActors(newelement.getStringValue());
                    }else{
                        bean.setAdversaryName(newelement.getStringValue());
                    }

                }
            }


        }else if (type == ACTOR_ADV){
            List actorTypeNodes = xmlDoc.selectNodes("/artwork/actors/actor[@name='Creature']");
            int actorTypeCount = actorTypeNodes.size();
            int typeRoll = StaticDiceRoller.rolldSomething(actorTypeCount, 1, true);
            if (typeRoll > 0) {
                DefaultElement actorTypeElement = (DefaultElement)actorTypeNodes.get(typeRoll-1);
                String newPath = actorTypeElement.getPath() + "[@name='Creature']/what/element";
                List actorList = xmlDoc.selectNodes(newPath);
                int actorCount = actorList.size();
                int actorListRoll = StaticDiceRoller.rolldSomething(actorCount, 1, true);
                if (actorListRoll > 0) {
                    DefaultElement newelement = (DefaultElement)actorList.get(actorListRoll-1);
                    bean.setAdversaryName(newelement.getStringValue());
                }
            }
        }
    }

    private void getLocation(IdeaBean bean) throws Exception {
        List locationTypeNodes = xmlDoc.selectNodes("/artwork/where/location");
        int locationTypeCount = locationTypeNodes.size();
        int typeRoll = StaticDiceRoller.rolldSomething(locationTypeCount, 1, true);
        if (typeRoll > 0) {
            DefaultElement locationTypeElement = (DefaultElement)locationTypeNodes.get(typeRoll-1);

            bean.setLocationType(locationTypeElement.attribute("name").getStringValue());

            String newPath = locationTypeElement.getPath() + "[@name='"+locationTypeElement.attribute("name").getStringValue()+"']/place";
            List placeList = xmlDoc.selectNodes(newPath);
            int placeCount = placeList.size();
            int placeListRoll = StaticDiceRoller.rolldSomething(placeCount, 1, true);
            if (placeListRoll > 0) {
                DefaultElement placeElement = (DefaultElement)placeList.get(placeListRoll-1);

                bean.setLocationName(placeElement.attribute("name").getStringValue());

                //Randomly determine to use a custom activity for this location, or a global one
                String actionPath = placeElement.getPath() + "[@name='"+placeElement.attribute("name").getStringValue()+"']/activity";
                List activityList = xmlDoc.selectNodes(actionPath);
                int activityCount = activityList.size();
                boolean useGlobal = false;
                if (activityList.size() <= 0){
                    useGlobal = true;
                }else{
                   int flip = StaticDiceRoller.rolldSomething(2, 1, true);
                    if (flip == 1){
                        useGlobal = true;
                    }
                }

                if (useGlobal){
                    List globalActivityNodes = null;
                    if (bean.getLocationType().equals("indoors")){
                        globalActivityNodes=xmlDoc.selectNodes("/artwork/indoorActions/activity");
                    }else{
                        globalActivityNodes=xmlDoc.selectNodes("/artwork/outdoorActions/activity");                        
                    }
                    int globalTypeCount = globalActivityNodes.size();
                    int globalTypeRoll = StaticDiceRoller.rolldSomething(globalTypeCount, 1, true);
                    if (globalTypeRoll > 0){
                        DefaultElement globalLocationElement = (DefaultElement)globalActivityNodes.get(globalTypeRoll-1);
                        bean.setActionName(globalLocationElement.getStringValue());
                        bean.setActionType(globalLocationElement.attribute("flag").getStringValue());                        
                    }


                }else{
                    int activityListRoll = StaticDiceRoller.rolldSomething(activityCount, 1, true);
                    if (activityListRoll > 0) {
                        DefaultElement activityElement = (DefaultElement)activityList.get(activityListRoll-1);
                        bean.setActionName(activityElement.getStringValue());
                        bean.setActionType(activityElement.attribute("flag").getStringValue());
                    }
                }


            }
        }
    }

    private void getSeason(IdeaBean bean) throws Exception {
        List seasonNodes = xmlDoc.selectNodes("/artwork/when/seasons/season");
        int seasonCount = seasonNodes.size();
        int roll = StaticDiceRoller.rolldSomething(seasonCount, 1, true);
        if (roll > 0){
            DefaultElement seasonElement = (DefaultElement)seasonNodes.get(roll-1);
            bean.setSeason(seasonElement.getStringValue());
        }

    }


    private void getTime(IdeaBean bean) throws Exception {
        List timeNodes = xmlDoc.selectNodes("/artwork/when/times/time");
        int timeCount = timeNodes.size();
        int roll = StaticDiceRoller.rolldSomething(timeCount, 1, true);
        if (roll > 0){
            DefaultElement timeElement = (DefaultElement)timeNodes.get(roll-1);
            bean.setTimeOfDay(timeElement.getStringValue());
        }
    }

    public static void main(String[] args) throws Exception {
        ArtworkIdeaGenerator idea = new ArtworkIdeaGenerator();
        idea.generateIdea();
    }


    public class IdeaBean{
        private String numberOfActors = "";
        private String actors = "";
        private String locationType = "";
        private String locationName = "";
        private String actionType = "";
        private String actionName = "";
        private String adversaryNumber = "";
        private String adversaryName = "";
        private String season = "";
        private String timeOfDay = "";
        private ArrayList backgroundElements = new ArrayList();

        public ArrayList getBackgroundElements() {
            return backgroundElements;
        }

        public void setBackgroundElements(ArrayList backgroundElements) {
            this.backgroundElements = backgroundElements;
        }

        public String getNumberOfActors() {
            return numberOfActors;
        }

        public void setNumberOfActors(String numberOfActors) {
            this.numberOfActors = numberOfActors;
        }

        public String getActors() {
            return actors;
        }

        public void setActors(String actors) {
            this.actors = actors;
        }

        public String getLocationType() {
            return locationType;
        }

        public void setLocationType(String locationType) {
            this.locationType = locationType;
        }

        public String getLocationName() {
            return locationName;
        }

        public void setLocationName(String locationName) {
            this.locationName = locationName;
        }

        public String getActionType() {
            return actionType;
        }

        public void setActionType(String actionType) {
            this.actionType = actionType;
        }

        public String getActionName() {
            return actionName;
        }

        public void setActionName(String actionName) {
            this.actionName = actionName;
        }

        public String getAdversaryNumber() {
            return adversaryNumber;
        }

        public void setAdversaryNumber(String adversaryNumber) {
            this.adversaryNumber = adversaryNumber;
        }

        public String getAdversaryName() {
            return adversaryName;
        }

        public void setAdversaryName(String adversaryName) {
            this.adversaryName = adversaryName;
        }

        public String getSeason() {
            return season;
        }

        public void setSeason(String season) {
            this.season = season;
        }

        public String getTimeOfDay() {
            return timeOfDay;
        }

        public void setTimeOfDay(String timeOfDay) {
            this.timeOfDay = timeOfDay;
        }
    }
}
